package com.quik.backend.service.billing;

import java.text.DecimalFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.quik.backend.mapper.BaseDao;
import com.quik.backend.mapper.BizBillingServiceDao;
import com.quik.backend.service.BaseServiceImpl;
import com.quik.backend.service.worker.DtaWorkerService;
import com.quik.entity.BizBilling;
import com.quik.entity.BizBillingItem;
import com.quik.entity.BizBillingRelatedItem;
import com.quik.entity.BizBillingService;
import com.quik.entity.DtaProduct;
import com.quik.entity.DtaToken;
import com.quik.entity.DtaWorker;
import com.quik.entity.SysAccount;
import com.quik.util.CommonUtils;
import com.quik.util.Tools;

@Service
@SuppressWarnings("unchecked")
public class BillingServiceImpl extends BaseServiceImpl implements
		BillingService {

	@Autowired
	private BizBillingServiceDao dao;

	@Autowired
	private DtaWorkerService dtaWorkerService;
	private DecimalFormat f = new DecimalFormat("00000");

	public BaseDao getDao() {
		return dao;
	}

	public String generateBillingNo() {
		String dateNo;
		try {
			dateNo = Tools.date2String8(new Date());
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		Integer qty = (Integer) this.dao.get("queryBizBillingCountByDateNo",
				dateNo);
		return dateNo + "-" + f.format(qty);
	}

	@Override
	public BizBilling submitTokenToOpen(String[] tokenNos,
			String contactStaffNo, SysAccount account) throws Exception {
		// 1.新增biz_billing
		String billingNo = generateBillingNo(); // 获得帐单编号
		BizBilling bizBilling = new BizBilling();
		bizBilling.setBilling_no(billingNo);
		bizBilling.setContact_staff_no(contactStaffNo);
		bizBilling.setIf_master(BizBilling.MASTER_YES);
		CommonUtils.setUpCrtMode(bizBilling, account);
		dao.insert(bizBilling);
		Integer billingId = bizBilling.getId();
		for (String tokenNo : tokenNos) {
			// 2.新增biz_billing_related_item表
			BizBillingRelatedItem relatedItem = new BizBillingRelatedItem();
			relatedItem.setBilling_id(billingId);
			relatedItem.setItem_no(tokenNo);
			relatedItem.setItem_type(BizBillingRelatedItem.ITEM_TYPE_TOKEN);
			CommonUtils.setUpCrtMode(relatedItem, account);
			dao.insert(relatedItem);

			List<DtaProduct> products = dao.load("findTokenBoundProduct",
					tokenNo);
			for (DtaProduct product : products) {
				if (product != null && product.getProduct_no().length() > 0) {
					BizBillingItem billingItem = new BizBillingItem();
					billingItem.setBilling_id(billingId);
					billingItem.setProduct_no(product.getProduct_no());
					billingItem.setQty(1);
					billingItem.setToken_no(tokenNo);
					billingItem.setIs_free(BizBillingItem.STATUS_NO);
					billingItem.setIs_subtract(BizBillingItem.STATUS_NO);
					billingItem.setContact_staff_no(contactStaffNo);
					billingItem.setPrice(product.getPrice());
					CommonUtils.setUpCrtMode(billingItem, account);
					billingItem
							.setStatus(BizBillingItem.BILLING_ITEM_STATUS_NORMAL);
					billingItem.setProduct_name(product.getProduct_name());

					if (product.getIf_need_worker().equals(
							DtaProduct.OPTION_FOR_YES)) {
						billingItem
								.setServe_status(BizBillingItem.BILLING_ITEM_SERVE_STATUS_READY);
					}
					if (product.getIf_chess_room().equals(
							DtaProduct.OPTION_FOR_YES)) {
						billingItem
								.setServe_status(BizBillingItem.BILLING_ITEM_ROOM_STATUS_READY);
					}
					dao.insert(billingItem);
					if (product.getIf_need_worker().equals(
							DtaProduct.OPTION_FOR_YES)) {
						BizBillingService billingService = new BizBillingService();
						billingService.setBilling_item_id(billingItem.getId());
						billingService
								.setStatus(BizBillingService.BILLING_SERVICE_STATUS_NORMAL);
						billingService.setTurn_type("lunCall");
						CommonUtils.setUpCrtMode(billingService, account);
						dao.insert(billingService);
					}
				}
			}
			DtaToken token = (DtaToken) dao.queryOneByProp(DtaToken.class,
					"token_no", tokenNo);
			token.setStatus(DtaToken.TOKEN_STATUS_USED);
			CommonUtils.setUpCrtMode(token, account);
			dao.updateByFull(token);
		}
		return bizBilling;
	}

	@Override
	public void updateBillingServiceIfNotNull(
			BizBillingService bizBillingService, SysAccount account) {
		BizBillingService obj = (BizBillingService) dao.queryById(
				BizBillingService.class, bizBillingService.getId());
		if (!StringUtils.isEmpty(bizBillingService.getTurn_type())) {
			obj.setTurn_type(bizBillingService.getTurn_type());
		}
		if (!StringUtils.isEmpty(bizBillingService.getCall_turn_worker_no())) {
			obj.setCall_turn_worker_no(bizBillingService
					.getCall_turn_worker_no());
		}
		if (!StringUtils.isEmpty(bizBillingService.getWorker_no())) {
			String workerNo = bizBillingService.getWorker_no();
			DtaWorker worker = (DtaWorker) dao.queryOneByProp(DtaWorker.class,
					"worker_no", workerNo);
			if (!DtaWorker.STATUS_FREE.equals(worker.getStatus())) {
				throw new RuntimeException("技师不是空闲状态，请选择其他技师.");
			}
			obj.setWorker_no(workerNo);
		}
		CommonUtils.setUpCrtMode(obj, account);
		dao.updateByFull(obj);
	}

	@Override
	public void updateBillingItemForCancel(Integer id, String staffNo,
			String password, SysAccount account) {
		BizBillingItem billingItem = (BizBillingItem) dao.queryById(
				BizBillingItem.class, id);
		if (billingItem == null)
			throw new RuntimeException("数据不正确，请重新操作.");
		boolean ifServe = !StringUtils.isEmpty(billingItem.getServe_status());
		boolean ifDoing = BizBillingItem.BILLING_ITEM_ROOM_STATUS_ONGOING
				.equals(billingItem.getServe_status())
				|| BizBillingItem.BILLING_ITEM_SERVE_STATUS_SERVING
						.equals(billingItem.getServe_status());
		boolean ifEnd = BizBillingItem.BILLING_ITEM_ROOM_STATUS_END
				.equals(billingItem.getServe_status())
				|| BizBillingItem.BILLING_ITEM_SERVE_STATUS_END
						.equals(billingItem.getServe_status());
		boolean ifNeedApprover = ifServe && (ifDoing || ifEnd) || !ifServe;
		billingItem.setStatus(BizBillingItem.BILLING_ITEM_STATUS_CANCELLED);
		if (ifNeedApprover) {
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("staff_no", staffNo);
			SysAccount approver = (SysAccount) dao.queryOneByMap(
					SysAccount.class, params);
			boolean ifPasswordValid = CommonUtils.validatePassword(password,
					approver.getOperate_password());
			if (!ifPasswordValid) {
				throw new RuntimeException("帐号密码不正确，操作取消.");
			}
		}
		if (ifServe && !ifEnd) {
			billingItem
					.setServe_status(BizBillingItem.BILLING_ITEM_ROOM_STATUS_END);
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("billing_item_id", id);
			List<BizBillingService> services = this.dao.queryByMap(
					BizBillingService.class, params);
			params = new HashMap<String, Object>();
			for (BizBillingService service : services) {
				params.put("worker_no", service.getWorker_no());
				DtaWorker dtaWorker = (DtaWorker) CommonUtils.queryOne(dao
						.queryByMap(DtaWorker.class, params));
				if (DtaWorker.STATUS_SERVICE.equals(dtaWorker.getStatus())) {
					CommonUtils.setUpCrtMode(dtaWorker, account);
					dtaWorkerService.updateWorkerToFree(dtaWorker);
				}
			}
		}
		CommonUtils.setUpCrtMode(billingItem, account);
		dao.updateByFull(billingItem);
	}

	@Override
	public BizBilling findBillingByToken(String tokenNo) {
		return (BizBilling) CommonUtils.queryOne(this.dao.load(
				"queryBizBillingByRelatedTokenNo", tokenNo));
	}

	@Override
	public List<BizBillingItem> findBillingItemByBillingId(String billingId) {
		return this.dao.load("queryBillingItemByBillingIdWithGroup",
				billingId);
	}

	@Override
	public void updateBillingItemForEnd(Integer id, SysAccount account) {
		BizBillingItem billingItem = (BizBillingItem) dao.queryById(
				BizBillingItem.class, id);
		if (billingItem == null)
			throw new RuntimeException("数据不正确，请重新操作.");
		boolean ifServe = !StringUtils.isEmpty(billingItem.getServe_status());
		boolean ifDoing = BizBillingItem.BILLING_ITEM_ROOM_STATUS_ONGOING
				.equals(billingItem.getServe_status())
				|| BizBillingItem.BILLING_ITEM_SERVE_STATUS_SERVING
						.equals(billingItem.getServe_status());
		if (ifServe && ifDoing) {
			billingItem
					.setServe_status(BizBillingItem.BILLING_ITEM_ROOM_STATUS_END);
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("billing_item_id", id);
			List<BizBillingService> services = this.dao.queryByMap(
					BizBillingService.class, params);
			params = new HashMap<String, Object>();
			for (BizBillingService service : services) {
				params.put("worker_no", service.getWorker_no());
				DtaWorker dtaWorker = (DtaWorker) CommonUtils.queryOne(dao
						.queryByMap(DtaWorker.class, params));
				if (DtaWorker.STATUS_SERVICE.equals(dtaWorker.getStatus())) {
					CommonUtils.setUpCrtMode(dtaWorker, account);
					dtaWorkerService.updateWorkerToFree(dtaWorker);
				}
			}
			CommonUtils.setUpCrtMode(billingItem, account);
			dao.updateByFull(billingItem);
		} else {
			throw new RuntimeException("数据不正确，请重新操作.");
		}
	}

	@Override
	public void submitBillingItemForKickoff(Integer billingItemId,
			String tokenNo, Integer[] serviceIds, String[] workerNos,
			String[] turnTypes, String[] callTurnWorkerNos, SysAccount account) {
		BizBillingItem billingItem = (BizBillingItem) this.dao.queryById(
				BizBillingItem.class, billingItemId);
		DtaProduct product = (DtaProduct) this.dao.queryOneByProp(
				DtaProduct.class, "product_no", billingItem.getProduct_no());
		Date sdate = new Date();
		billingItem.setStart_time(sdate);
		Date edate = new Date(product.getLen_of_min() * 60L * 1000
				+ sdate.getTime());
		billingItem.setPlan_end_time(edate);
		billingItem
				.setServe_status(BizBillingItem.BILLING_ITEM_SERVE_STATUS_SERVING);
		CommonUtils.setUpCrtMode(billingItem, account);
		this.dao.updateByFull(billingItem);
		for (int i = 0; i < serviceIds.length; i++) {
			Integer serviceId = serviceIds[i];
			String workerNo = workerNos[i];
			String turnType = turnTypes[i];
			DtaWorker worker = (DtaWorker) CommonUtils.queryOne(this.dao
					.queryByProp(DtaWorker.class, "worker_no", workerNo));
			if (!DtaWorker.STATUS_FREE.equals(worker.getStatus())) {
				throw new RuntimeException("技师已经被分配，请选择其他技师.");
			}
			BizBillingService bbs = (BizBillingService) this.dao.queryById(
					BizBillingService.class, serviceId);
			bbs.setWorker_no(workerNo);
			if (callTurnWorkerNos != null && callTurnWorkerNos.length > 0) {
				String callTurnWorkerNo = callTurnWorkerNos[i];
				bbs.setCall_turn_worker_no(callTurnWorkerNo);
			}
			bbs.setTurn_type(turnType);
			this.dao.updateByFull(bbs);
		}
	}

	@Override
	public Integer submitProductToBilling(Integer billingId,
			String[] productNos, Integer[] qtys, String roomNo, String tokenNo,
			String staff_no) {
		for (int i = 0; i < productNos.length; i++) {
			String productNo = productNos[i];
			Integer qty = qtys[i];
			DtaProduct product = (DtaProduct) dao.queryOneByProp(DtaProduct.class,
					"product_no", productNo);
			if (DtaProduct.OPTION_FOR_YES.equals(product.getIf_need_worker())) {
				for (int j = 0; j < qty; j++) {
					BizBillingItem item = getBizBillingItem(product, tokenNo,
							roomNo, 1, staff_no);
					item.setBilling_id(billingId);
					dao.insert(item);
					if (product.getNum_of_worker() == null
							|| product.getNum_of_worker() < 1) {
						BizBillingService billingService = this
								.getBizBillingService(item.getId(), staff_no,
										product);
						dao.insert(billingService);
					} else {
						for (int k = 0; k < product.getNum_of_worker(); k++) {
							BizBillingService billingService = this
									.getBizBillingService(item.getId(),
											staff_no, product);
							dao.insert(billingService);
						}
					}
				}
			} else if (DtaProduct.OPTION_FOR_YES.equals(product
					.getIf_chess_room())) {

				for (int j = 0; j < qty; j++) {
					BizBillingItem item = getBizBillingItem(product, tokenNo,
							roomNo, 1, staff_no);
					item.setBilling_id(billingId);
					dao.insert(item);
				}

			} else {
				BizBillingItem item = getBizBillingItem(product, tokenNo,
						roomNo, qty, staff_no);
				item.setBilling_id(billingId);
				dao.insert(item);
			}
		}
		return billingId;
	}

	private BizBillingItem getBizBillingItem(DtaProduct product,
			String tokenNo, String roomNo, Integer qty, String staffNo) {
		BizBillingItem item = new BizBillingItem();
		item.setProduct_no(product.getProduct_no());
		item.setProduct_name(product.getProduct_name());
		item.setCrt_date(new Date());
		item.setCrt_user(staffNo);
		item.setIs_free(BizBillingItem.STATUS_NO);
		item.setIs_subtract(BizBillingItem.STATUS_NO);
		item.setStatus(BizBillingItem.BILLING_ITEM_STATUS_NORMAL);
		if ("Y".equalsIgnoreCase(product.getIf_need_worker())) {
			item.setServe_status(BizBillingItem.BILLING_ITEM_SERVE_STATUS_READY);
		} else if ("Y".equalsIgnoreCase(product.getIf_chess_room())) {
			item.setServe_status(BizBillingItem.BILLING_ITEM_SERVE_STATUS_READY);
		} else {
			item.setServe_status(BizBillingItem.BILLING_ITEM_SERVE_STATUS_END);
		}
		item.setToken_no(tokenNo);
		item.setRoom_no(roomNo);
		item.setQty(qty);
		return item;
	}

	private BizBillingService getBizBillingService(Integer billingItemId,
			String staffNo, DtaProduct product) {
		BizBillingService billingService = new BizBillingService();
		billingService.setBilling_item_id(billingItemId);
		billingService
				.setStatus(BizBillingService.BILLING_SERVICE_STATUS_NORMAL);
		billingService.setCrt_user(staffNo);
		billingService.setCrt_date(new Date());
		billingService.setMod_date(new Date());
		billingService.setMod_user(staffNo);
		billingService.setTurn_type("lunCall");
		/*
		 * if(product!=null){
		 * billingService.setNum_of_hour(product.getNum_of_hour()); }
		 */
		return billingService;
	}

}
